/*
 * Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "sle_flow_monitor_manager.h"
#include "sle_hilog.h"

namespace OHOS {
namespace NearLink {
namespace SleStandard {
SleFlowMonitorManager::SleFlowMonitorManagerImpl::SleFlowMonitorManagerImpl()
{
    timer_ = std::make_unique<Timer>([this] {CalculateFlow();});
}

SleFlowMonitorManager::SleFlowMonitorManagerImpl::~SleFlowMonitorManagerImpl()
{
    timer_ = nullptr;
}

SleErrorCode SleFlowMonitorManager::SleFlowMonitorManagerImpl::EnableMonitor()
{
    SLE_ASSERT_AND_RETURN_RET_LOG(timer_, SLE_ERR_NOT_READY, "timer state error!");
    bool ret = timer_->Start(FLOW_MONITOR_PERIOD, true);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret, SLE_ERR_FAILED, "enable monitor failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleFlowMonitorManager::SleFlowMonitorManagerImpl::DisableMonitor()
{
    SLE_ASSERT_AND_RETURN_RET_LOG(timer_, SLE_ERR_NOT_READY, "timer state error!");
    bool ret = timer_->Stop();
    SLE_ASSERT_AND_RETURN_RET_LOG(ret, SLE_ERR_FAILED, "disable monitor failed!");
    return SLE_NO_ERROR;
}

void SleFlowMonitorManager::SleFlowMonitorManagerImpl::CalculateFlow()
{
    std::lock_guard<std::mutex> lock(flowLock_);
    float flow = (totalFlow_ * 1000) / FLOW_MONITOR_PERIOD; // byte/s
    callbacks_.ForEach([flow](ISleFlowMonitorManagerCallback &callback) {
        callback.OnFlowMonitorEvent(flow);
    });
    totalFlow_ = 0;
}

void SleFlowMonitorManager::SleFlowMonitorManagerImpl::AccumulateFlow(float flow)
{
    std::lock_guard<std::mutex> lock(flowLock_);
    totalFlow_ += flow;
}

SleFlowMonitorManager::SleFlowMonitorManager()
{
    pimpl_ = std::make_unique<SleFlowMonitorManagerImpl>();
    SLE_ASSERT_AND_RETURN_LOG(pimpl_, "pimpl null error!");
}

SleFlowMonitorManager::~SleFlowMonitorManager() {}

SleFlowMonitorManager SleFlowMonitorManager::instance_;
SleFlowMonitorManager *SleFlowMonitorManager::GetInstance()
{
    return &instance_;
}

SleErrorCode SleFlowMonitorManager::StartFlowMonitor()
{
    std::lock_guard<std::mutex> lock(lock_);
    SLE_ASSERT_AND_RETURN_RET_LOG(!MonitorEnable_, SLE_ERR_STATUS_WRONG, "monitor alread start error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(pimpl_, SLE_ERR_NOT_READY, "pimpl null error!");
    SleErrorCode ret = pimpl_->EnableMonitor();
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, SLE_ERR_FAILED, "start flow monitor failed!");
    MonitorEnable_ = true;
    return SLE_NO_ERROR;
}

SleErrorCode SleFlowMonitorManager::StopFlowMonitor()
{
    std::lock_guard<std::mutex> lock(lock_);
    SLE_ASSERT_AND_RETURN_RET_LOG(MonitorEnable_, SLE_ERR_STATUS_WRONG, "monitor not start error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(pimpl_, SLE_ERR_NOT_READY, "pimpl null error!");
    SleErrorCode ret = pimpl_->DisableMonitor();
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, SLE_ERR_FAILED, "stop flow monitor failed!");
    MonitorEnable_ = false;
    return SLE_NO_ERROR;
}

bool SleFlowMonitorManager::IsEnableMonitor()
{
    return MonitorEnable_;
}

void SleFlowMonitorManager::WriteDataVolume(float flow)
{
    pimpl_->AccumulateFlow(flow);
}

SleErrorCode SleFlowMonitorManager::RegisterMonitorCallback(ISleFlowMonitorManagerCallback &callback)
{
    SLE_LOGD("RegisterMonitorCallback In");
    SLE_ASSERT_AND_RETURN_RET_LOG(pimpl_, SLE_ERR_NOT_READY, "pimpl_ null error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(pimpl_->callbacks_.Register(callback), SLE_ERR_FAILED,
        "register monitor callback failed!");
    return SLE_NO_ERROR;
}

SleErrorCode SleFlowMonitorManager::UnregisterMonitorCallback(ISleFlowMonitorManagerCallback &callback)
{
    SLE_LOGD("UnregisterMonitorCallback In");
    SLE_ASSERT_AND_RETURN_RET_LOG(pimpl_, SLE_ERR_NOT_READY, "pimpl null error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(pimpl_->callbacks_.Unregister(callback), SLE_ERR_FAILED,
        "unregister monitor callback failed!");
    return SLE_NO_ERROR;
}
} // SleStandard
} // NearLink
} // OHOS